#include "../libc/list.h"
#include "pci.h"
#include "usb.h"

extern list_t *pci_list;

static void do_usb_init(pci_dev_t *d);
static int ehci_reset(ehci_regs_t *r);
static void ehci_control_xfer(ehci_regs_t *r);
static void print_datas(ehci_regs_t *r, qh_t *qh, qtd_t *qtd);
static void print_regs(ehci_regs_t *r);
static void print_cap_regs(ehci_cap_regs_t *r);
static void print_usb_device_descriptor(usb_device_desc *desc);
static void print_usb_config_descriptor(usb_config_desc *desc);
static void print_usb_interface_descriptor(usb_interface_desc *desc);

static uint8_t __attribute__((aligned(4096))) buf[8224];

static inline void mmio_write32(uintptr_t addr, uint32_t val)
{
    *(volatile uint32_t *)addr = val;
}
static inline uint32_t mmio_read32(uintptr_t addr)
{
    return *(volatile uint32_t *)addr;
}
static inline uint8_t mmio_read8(uintptr_t addr)
{
    return *(volatile uint8_t *)addr;
}
static inline uint16_t mmio_read16(uintptr_t addr)
{
    return *(volatile uint16_t *)addr;
}

int usb_init() {
    kprint("usb_init start\n");
    if(pci_list->size == 0) return 0;
    node_t *n = &(pci_list->n);
    int i;
    char str[20];
    for(i = 0; i < pci_list->size;i++) {
        n = n->next;
        pci_dev_t *d = n->data;
        if(d->class_code == 0x0c && d->sub_class == 0x03 && d->proif == 0x20) {
            kprint("find ehci\n");
            do_usb_init(d);
        }
    }
    return 0;
}

void usb_read(int sector, uint8_t *addr);

static void do_usb_init(pci_dev_t *d) {
    ehci_cap_regs_t *cap = (ehci_cap_regs_t *) d->bar[0];
    kprint("ehci capability registers:\n");
    print_cap_regs(cap);
    ehci_regs_t *r = (ehci_regs_t *)(d->bar[0] + cap->cap_len);
    int res = ehci_reset(r);
    ehci_control_xfer(r);
    // 设备描述符
    uint8_t *desc = buf + 128 + sizeof(qtd_t) * 4;
    if (desc[0] == 0x12 && desc[1] == 0x01) {
        // 成功获取
        
    }
}

static int ehci_reset(ehci_regs_t *r)
{
    /* 停止调度 */
    mmio_write32((uintptr_t)&r->usbcmd, 0);

    /* 等待 RUN 位清 0 */
    while (mmio_read32((uintptr_t)&r->usbcmd) & (1 << 0))
        ;

    /* 复位控制器 */
    mmio_write32((uintptr_t)&r->usbcmd, EHCI_USBCMD_RESET);
    while (mmio_read32((uintptr_t)&r->usbcmd) & EHCI_USBCMD_RESET)
        ;

    kprint("after ehci reset:\n");
    print_regs(r);

    /* 启动ehci */
    mmio_write32((uintptr_t)&r->usbcmd, EHCI_USBCMD_RUN);

    /* 路由端口到 EHCI */
    mmio_write32((uintptr_t)&r->configflag, EHCI_CONFIGFLAG);

    kprint("after ehci start:\n");
    print_regs(r);

    /* 打开端口电源并等待连接 */
    // PPC为0 不能设置端口电源
    // mmio_write32((uintptr_t)&r->portsc[0],
    //     mmio_read32((uintptr_t)&r->portsc[0]) | EHCI_PORTSC_POWERON);
    while (!(mmio_read32((uintptr_t)&r->portsc[0]) & 1))
        ;

    kprint("after port0 connected:\n");
    print_regs(r);
    
    /* 端口复位 */
    mmio_write32((uintptr_t)&r->portsc[0],
        mmio_read32((uintptr_t)&r->portsc[0]) | EHCI_PORTSC_RESET | EHCI_PORTSC_ENABLE);
    // 等待10ms
    int count = 10000000;
    while (count-- > 0);
    mmio_write32((uintptr_t)&r->portsc[0],
        mmio_read32((uintptr_t)&r->portsc[0]) & ~EHCI_PORTSC_RESET);
    while ((mmio_read32((uintptr_t)&r->portsc[0]) & EHCI_PORTSC_RESET))
        ;

    kprint("after port0 reset:\n");
    print_regs(r);
    
    kprint("ehci_rest finished!\n");
}

/* 构建一个控制传输：SETUP -> DATA -> STATUS */
static void ehci_control_xfer(ehci_regs_t *r)
{
    kprint("ehci_control_xfer start!\n");
    /* 描述符放在 4K 对齐缓冲区 */
    qh_t *qh  = (qh_t *)buf;
    qtd_t *qtd = (qtd_t *)(buf + 128);

    /* 设备描述符请求 8 字节 1:设备 2：配置+接口 */
    static const uint8_t setup[] = {
        0x80, 0x06, 0x00, 0x02, 0x00, 0x00, 0x12, 0x00
    };

    /* ---- 初始化 qTD ---- */
    /* SETUP qtd */
    qtd[0].next = (uintptr_t)&qtd[1];      /* 指向下一个 qTD，T=1 表示最后一个 */
    qtd[0].alt  = 1;                           /* 不跳转 */
    qtd[0].token = (8 << 16) | (2 << 8) | (1 << 7); /* 8 字节, PID=SETUP, Status=Active */

    /* DATA qtd */
    qtd[1].next = (uintptr_t)&qtd[2];
    qtd[1].alt  = 1;
    qtd[1].token = (4096 << 16) | (1 << 8) | (1 << 7); /* 8 字节, PID=IN   */

    /* STATUS qtd */
    qtd[2].next = 1;        /* 结束 */
    qtd[2].alt  = 1;
    qtd[2].token = (0 << 16) | (0 << 8) | (1 << 7) | (1 << 31); /* 0 字节, PID=OUT  */

    /* 复制 SETUP 数据到缓冲区 */
    uint8_t *setup_buf = (uint8_t *)&qtd[3];
    int i;
    for (i = 0; i < 8; i++) setup_buf[i] = setup[i];
    qtd[0].buf[0] = (uintptr_t)setup_buf;

    /* DATA 缓冲区 */
    uint8_t *data_buf = (uint8_t *)&qtd[4];
    qtd[1].buf[0] = (uintptr_t)data_buf;

    /* ---- 初始化 QH ---- */
    qh->horizontal = (uintptr_t)qh | 2;                 /* 终止 */
    qh->static_ep  = (0 << 27) |        /* C=0 */
                     (0 << 8)  |    /* 端点 0 */
                     (1 << 14) |    /* 硬件负责翻转data0/1 */
                     (1 << 15) |    /* Head of Reclamation List Flag */
                     (2 << 12);       /* 高速 */
    qh->ep_cap = 1 << 30;
    qh->current_qtd_phy = 0;
    qh->overlay.next_phy = qtd;
    qh->overlay.alt_next_phy = 1;
    qh->overlay.token = 0;
    for (int i = 0; i < 5; i++) {
		qh->overlay.buffer_phy[i] = 0;
		qh->overlay.ext_buffer_phy[i] = 0;
	}

    /* 把 QH 物理地址写进 ASYNCLIST */
    //print_regs(r, qh, qtd);
    mmio_write32((uintptr_t)&r->asynclistaddr, (uintptr_t)qh);
    //print_regs(r, qh, qtd);
    mmio_write32((uintptr_t)&r->usbcmd, (1 << 5) | 1); /* 打开异步调度 + RUN */
    //print_regs(r, qh, qtd);

    /* 轮询完成标志 */
    int count = 0;
    int count1 = 0;
    while (qtd[1].token & 0x80);

    kprint("after get device desripter:\n");
    print_datas(r, qh, qtd);
    usb_config_desc *desc = (usb_config_desc *)data_buf;
    usb_interface_desc *idesc = (usb_interface_desc *)(data_buf + 9);
    kprint("size of usb_config_desc: ");
    char *str[20];
    int2hex(sizeof(usb_config_desc), str);
    kprint(str);
    kprint("\n");
    kprint("usb config descriptor:\n");
    print_usb_config_descriptor(desc);
    kprint("usb interface descriptor:\n");
    print_usb_interface_descriptor(idesc);

    /* 关闭调度 */
    mmio_write32((uintptr_t)&r->usbcmd, 0);

    kprint("get device descripter finished!\n");
}

static void print_datas(ehci_regs_t *r, qh_t *qh, qtd_t *qtd) {
    char str[20];
    kprint("USBCMD: ");
    int2hex(mmio_read32((uintptr_t)&r->usbcmd), str);
    kprint(str);
    kprint(", USBSTS: ");
    int2hex(mmio_read32((uintptr_t)&r->usbsts), str);
    kprint(str);
    kprint(", ASYNCLISTADDR: ");
    int2hex(mmio_read32((uintptr_t)&r->asynclistaddr), str);
    kprint(str);
    kprint(", qtd[1].token: ");
    int2hex(qtd[1].token, str);
    kprint(str);
    kprint("\n");
}

static void print_regs(ehci_regs_t *r) {
    char str[20];
    kprint("USBCMD: ");
    int2hex(mmio_read32((uintptr_t)&r->usbcmd), str);
    kprint(str);
    kprint(", USBSTS: ");
    int2hex(mmio_read32((uintptr_t)&r->usbsts), str);
    kprint(str);
    kprint(", configflag: ");
    int2hex(mmio_read32((uintptr_t)&r->configflag), str);
    kprint(str);
    kprint(", portsc[0]: ");
    int2hex(mmio_read32((uintptr_t)&r->portsc[0]), str);
    kprint(str);
    kprint("\n");
}

static void print_cap_regs(ehci_cap_regs_t *r) {
    char str[20];
    kprint("cap_len: ");
    int2hex(mmio_read8((uintptr_t)&r->cap_len), str);
    kprint(str);
    kprint(", version: ");
    int2hex(mmio_read16((uintptr_t)&r->version), str);
    kprint(str);
    kprint(", sparams: ");
    int2hex(mmio_read32((uintptr_t)&r->sparams), str);
    kprint(str);
    kprint(", cparams: ");
    int2hex(mmio_read32((uintptr_t)&r->cparams), str);
    kprint(str);
    kprint("\n");
}

static void print_usb_device_descriptor(usb_device_desc *desc) {
    char str[20];
    kprint("bLength: ");
    int2hex(desc->bLength, str);
    kprint(str);
    kprint(", bDescriptorType: ");
    int2hex(desc->bDescriptorType, str);
    kprint(str);
    kprint(", bcdUSB: ");
    int2hex(desc->bcdUSB, str);
    kprint(str);
    kprint(", bDeviceClass: ");
    int2hex(desc->bDeviceClass, str);
    kprint(str);
    kprint(", bDeviceSubClass: ");
    int2hex(desc->bDeviceSubClass, str);
    kprint(str);
    kprint(", bDeviceProtocol: ");
    int2hex(desc->bDeviceProtocol, str);
    kprint(str);
    kprint(", bMaxPacketSize0: ");
    int2hex(desc->bMaxPacketSize0, str);
    kprint(str);
    kprint(", idVendor: ");
    int2hex(desc->idVendor, str);
    kprint(str);
    kprint(", idProduct: ");
    int2hex(desc->idProduct, str);
    kprint(str);
    kprint(", bcdDevice: ");
    int2hex(desc->bcdDevice, str);
    kprint(str);
    kprint(", iManufacturer: ");
    int2hex(desc->iManufacturer, str);
    kprint(str);
    kprint(", iProduct: ");
    int2hex(desc->iProduct, str);
    kprint(str);
    kprint(", iSerialNumber: ");
    int2hex(desc->iSerialNumber, str);
    kprint(str);
    kprint(", bNumConfigurations: ");
    int2hex(desc->bNumConfigurations, str);
    kprint(str);
    kprint("\n");
}


static void print_usb_config_descriptor(usb_config_desc *desc) {
    char str[20];
    kprint("bLength: ");
    int2hex(desc->bLength, str);
    kprint(str);
    kprint(", bDescriptorType: ");
    int2hex(desc->bDescriptorType, str);
    kprint(str);
    kprint(", wTotalLength: ");
    int2hex(desc->wTotalLength, str);
    kprint(str);
    kprint(", bNumInterfaces: ");
    int2hex(desc->bNumInterfaces, str);
    kprint(str);
    kprint(", bConfigurationValue: ");
    int2hex(desc->bConfigurationValue, str);
    kprint(str);
    kprint(", iConfiguration: ");
    int2hex(desc->iConfiguration, str);
    kprint(str);
    kprint(", bmAttributes: ");
    int2hex(desc->bmAttributes, str);
    kprint(str);
    kprint(", bMaxPower: ");
    int2hex(desc->bMaxPower, str);
    kprint(str);
    kprint("\n");
}

static void print_usb_interface_descriptor(usb_interface_desc *desc) {
    char str[20];
    kprint("bLength: ");
    int2hex(desc->bLength, str);
    kprint(str);
    kprint(", bDescriptorType: ");
    int2hex(desc->bDescriptorType, str);
    kprint(str);
    kprint(", bInterfaceNumber: ");
    int2hex(desc->bInterfaceNumber, str);
    kprint(str);
    kprint(", bAlternateSetting: ");
    int2hex(desc->bAlternateSetting, str);
    kprint(str);
    kprint(", bNumEndpoints: ");
    int2hex(desc->bNumEndpoints, str);
    kprint(str);
    kprint(", bInterfaceClass: ");
    int2hex(desc->bInterfaceClass, str);
    kprint(str);
    kprint(", bInterfaceSubClass: ");
    int2hex(desc->bInterfaceSubClass, str);
    kprint(str);
    kprint(", bInterfaceProtocol: ");
    int2hex(desc->bInterfaceProtocol, str);
    kprint(str);
    kprint(", iInterface: ");
    int2hex(desc->iInterface, str);
    kprint(str);
    kprint("\n");
}